"""
@author: 江同学呀
@file: inner_hits_options.py
@date: 2025/1/14 23:32
@desc:
    检索内部点击
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/inner-hits.html#inner-hits-options
"""
from typing import Union, Dict, Iterable, TYPE_CHECKING

from espc.orm.model.base.base import _Base

from espc.orm.model.dsl.search_fields import Source
if TYPE_CHECKING:
    from espc.orm.model.dsl.collapse_search_results import Collapse
from espc.orm.model.dsl.sort_search_results import Sort
from espc.orm.model.mapping.field.base_field.base_field import _BaseField


class InnerHits(_Base):
    """
    检索内部点击

    :param from_:
        The offset from where the first hit to fetch for each inner_hits in the returned regular search hits.
        在返回的常规搜索命中，为每个inner_hits获取的第一次点击的偏移量。
    :param size:
        The maximum number of hits to return per inner_hits. By default the top three matching hits are returned.
        每个inner_hits返回的最大点击数。默认情况下，将返回前三个匹配的点击。
    :param sort:
        How the inner hits should be sorted per inner_hits. By default the hits are sorted by the score.
        应如何按inner_hits对内部点击进行排序。默认情况下，点击按分数排序。
    :param name:
        The name to be used for the particular inner hit definition in the response. Useful when multiple inner hits
        have been defined in a single search request. The default depends in which query the inner hit is defined.
        For has_child query and filter this is the child type, has_parent query and filter this is the parent type and
        the nested query and filter this is the nested path.

        用于响应中特定内部点击定义的名称。在单个搜索请求中定义了多个内部点击时，此选项非常有用。默认值取决于在哪个查询中定义了内部点击。对于
        has_child查询和过滤器，这是子类型，has_parent查询和过滤器是父类型，嵌套查询和过滤器是嵌套路径。
    """

    def __init__(
            self, from_: int = None, size: int = None, sort: Union[_BaseField, Sort, str, Iterable[Sort]] = None,
            name: str = None, collapse: Union["Collapse", _BaseField] = None,
            source: Union[bool, str, Iterable[str], Iterable[_BaseField], _BaseField, Dict, Source] = None,
            docvalue_fields: Iterable[Union[str, _BaseField]] = None
    ):
        super().__init__()
        self._from: int = from_
        self._size: int = size
        self._sort: Union[_BaseField, Sort, str, Iterable[Sort]] = sort
        self._name: str = name
        self._collapse: Union["Collapse", _BaseField] = collapse
        self._source: Union[bool, str, Iterable[str], Iterable[_BaseField], _BaseField, Dict, Source] = source
        self._docvalue_fields: Iterable[Union[str, _BaseField]] = docvalue_fields
        return

    def _build(self) -> Dict:
        _body: dict = {}
        if self._from is not None:
            _body["from"] = self._from
        if self._size is not None:
            _body["size"] = self._size
        if self._sort:
            _body["sort"] = (
                self._sort
                if isinstance(self._sort, str)
                else (
                    self._sort._field_name
                    if isinstance(self._sort, (_BaseField))
                    else (
                        self._sort._build()
                        if isinstance(self._sort, Sort)
                        else [
                            sort._build() for sort in self._sort
                        ]
                    )
                )
            )
        if self._name:
            _body["name"] = self._name
        if self._collapse:
            _body["collapse"] = (
                self._collapse._build()
                if not isinstance(self._collapse, (_BaseField))
                else {
                    "field": self._collapse
                }
            )
        if self._source is not None:
            _body["_source"] = (
                self._source
                if isinstance(self._source, (bool, str, Dict))
                else (
                    self._source._build()
                    if isinstance(self._source, Source)
                    else (
                        self._source._field_name
                        if isinstance(self._source, (_BaseField))
                        else [field if isinstance(field, str) else field._field_name for field in self._source]
                    )
                )
            )
        if self._docvalue_fields:
            _body["docvalue_fields"] = [
                field if isinstance(field, str) else field._field_name
                for field in self._docvalue_fields
            ]
        return _body

